package filters;

import draw.ExploringMedics;
import java.util.Arrays;

public class LocalColorFilter extends AbstractColorFilter {

    Statistic global = null;
    final int CELLS = 256;
    final int STEP;
    final int window = 5;
    int correctedImage[][] = null;
    final double E = 2.0;
    final double k0 = 0.7;
    final double k1 = 0.01;
    final double k2 = 2.3;    //improove black regions
//    final double k2 = 0.7;    //improove white regions

    public LocalColorFilter(int[][] imageDescription) {
        super(imageDescription);
        STEP = 256 / CELLS;

        correctedImage = new int[width][height];
        for (int i = 0; i < width; i++) {
            System.arraycopy(imageDescription[i], 0, correctedImage[i], 0, height);
        }
    }

    @Override
    public void doFilted() {
        global = countStatistic(new Bound(0, 0, width, height));
        int improved = 0;
        int enter = 0;
        for (int i = 0; i < width - window; i++) {
            for (int j = 0; j < height - window; j++) {
                enter++;
                Statistic current = countStatistic(new Bound(i, j, window, window));
                if (improve(current)) {
                    correctedImage[i + window / 2][j + window / 2] =
                            (int) (imageDescription[i + window / 2][j + window / 2] * E);
                    if (correctedImage[i + window / 2][j + window / 2] > ExploringMedics.WHITE) {
                        correctedImage[i + window / 2][j + window / 2] = ExploringMedics.WHITE;
                    }
                    improved++;

                }
            }
        }
        System.out.println(improved + " " + enter);
    }

    @Override
    public int[][] getImageDescription() {
        return correctedImage;
    }

    boolean improve(Statistic stat) {

        if (stat.m <= k0 * global.m
                && k1 * global.sigma <= stat.sigma
                && stat.sigma <= k2 * global.sigma) {
            return true;
        }
        return false;
    }

    Statistic countStatistic(Bound bounds) {

        double histogram[] = countHistogram(bounds);

        double m = 0;
        double sigma = 0;

        for (int i = 0; i < CELLS; i += STEP) {
            m += i * histogram[i / STEP];
        }

        for (int i = 0; i < CELLS; i += STEP) {
            sigma += (i - m) * (i - m) * histogram[i / STEP];
        }

        sigma = Math.sqrt(sigma);

        return new Statistic(m, sigma);
    }

    double[] countHistogram(Bound bounds) {
        double hisogram[] = new double[CELLS];
        Arrays.fill(hisogram, 0);

        for (int i = bounds.x; i < bounds.xEnd; i++) {
            for (int j = bounds.y; j < bounds.yEnd; j++) {
                hisogram[imageDescription[i][j]]++;
            }
        }

        int square = bounds.getSqure();

        for (int i = 0; i < CELLS; i++) {
            hisogram[i] /= square;
        }

        return hisogram;
    }

    private class Bound {

        public int x = 0;
        public int y = 0;
        private int width = 0;
        private int height = 0;
        public int xEnd = 0;
        public int yEnd = 0;

        public Bound(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            xEnd = x + width;
            yEnd = y + height;
        }

        public int getSqure() {
            return width * height;
        }
    }

    private class Statistic {

        public double sigma = 0;
        public double m = 0;

        public Statistic(double sigme, double m) {
            this.sigma = sigme;
            this.m = m;
        }
    }
}
